package com.yystar.security.support.util;

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.LinkedHashSet;
import java.util.List;

import org.apache.commons.lang.StringUtils;


public class EntityGenerator {
	private static String fileName = "";
	
	private static String packageName = "com.yystar.bas.team.domain";
	private static String tableNames = "Team";
	private static String tableName = "";
	private static String userName = "root";
	private static String password = "Admin123";
	private final static String databaseName = "newBas";
	public static Connection con = null;
	public static PreparedStatement ps = null;
	public static ResultSet rs = null;
	private final static String DRIVER = "com.mysql.jdbc.Driver";
	private final static String URL = "jdbc:mysql://10.0.2.53:3306/"+databaseName;

	public static void main(String[] args) throws SQLException, IOException {
		//TODO create all entity of database.
		List<String> tableNames = getTablesName();
//		String tableName = ;
		for (String tn : tableNames) {
			tableName = tn;
			fileName = toCamelCase(tn);
			generateEntityFile(generateClassFile(), fileName, getPath());
		}
		
		
		
		//Create single entity.
//		tableName = "sport";
//		fileName = toCamelCase(Sport.class.getSimpleName());
//		generateEntityFile(generateClassFile(), fileName, getPath());
		
	}
	
	public static String getPath(){
		String path = System.getProperty("user.dir");
		String base = "\\src\\main\\java\\";
		path += base;
		String [] packages = packageName.split("\\.");
		for (String str : packages) {
			path += str + "\\";
		}
		return path;
	}
	
	public static List<String> getTablesName() throws SQLException{
		if(!"".equals(tableNames)){
			return Arrays.asList(tableNames.split(","));
		}
		List<String> tableNames = new ArrayList<String>();
		Connection connection = getConn();
		String sql = "show tables";
		ps = connection.prepareStatement(sql);
		rs = ps.executeQuery();
		while(rs.next()){
//			System.out.println(rs.getString("Tables_in_shopping"));
			tableNames.add(rs.getString("Tables_in_"+databaseName));
		}
		closeAll(connection, ps, rs);
		return tableNames;
		
	}
	
	/**
	 * 获取表的列名
	 * @param tableName
	 * @return
	 * @throws SQLException
	 */
	public static List<String> getColumnNames(String tableName) throws SQLException{
		List<String> columnNames = new ArrayList<String>();
		String sql = "select * from " + tableName;
		Connection connection = getConn();
		ps = connection.prepareStatement(sql);
		rs = ps.executeQuery();
		int columnCount = rs.getMetaData().getColumnCount();
		for(int i = 1;i<columnCount ; i ++){
			System.out.println(rs.getMetaData().getColumnName(i));
		}
		closeAll(connection, ps, rs);
		return columnNames;
	}

	/**
	 * 获取连接
	 * @return
	 */
	public static Connection getConn() {
		Connection con = null;
		try {
			Class.forName(DRIVER);
			con = DriverManager.getConnection(URL, userName, password);
		} catch (ClassNotFoundException e) {
			System.out.println(e.getMessage());
			e.printStackTrace();
		} catch (SQLException e) {
			System.out.println(e.getMessage());
			e.printStackTrace();
		}

		return con;
	}

	/**
	 * 关闭数据库连接
	 * @param con
	 * @param ps
	 * @param rs
	 */
	public static void closeAll(Connection con, PreparedStatement ps,
			ResultSet rs) {
		try {

			if (ps != null) {
				ps.close();
			}

			if (rs != null) {
				rs.close();
			}
			if (con != null) {
				con.close();
			}
		} catch (SQLException e) {
			e.printStackTrace();
		}

	}

	public static void addParams(Object[] params, PreparedStatement ps)
			throws SQLException {
		if (params == null || params.length == 0)
			return;
		int i = 1;
		for (Object o : params) {
			ps.setObject(i, o);
			i++;
		}
	}
	
	public static void addJavaTypes(LinkedHashSet<String> javaTypes,String canonicalName){
		javaTypes.add(generateImportPackage(canonicalName));
	}

	public static StringBuilder generateClassFile() throws SQLException {
		StringBuilder sb = new StringBuilder();
		sb.append(generatePackage());
		LinkedHashSet<String> javaTypes = new LinkedHashSet<String>();
		StringBuilder sbClassBody = generateClassFileStr(javaTypes,tableName);
		addJavaTypes(javaTypes,"com.yystar.bas.support.base.BaseDomain");
		addJavaTypes(javaTypes,"javax.persistence.Table");
		sb.append(getImportPackage(javaTypes));
		String className = upperCaseFirst(tableName);
		if(className.contains("_")){
			className = toCamelCase(className);
		}
		sb.append(generateClassDeclaration(className));
		sb.append(sbClassBody);
		sb.append("}");
		return sb;
	}
	
	public static String toCamelCase(String str){
		String []strArray = str.split("_");
		String camelCase = StringUtils.EMPTY;
		for (String s : strArray) {
			camelCase += upperCaseFirst(s);
		}
		return camelCase;
	}

	public static StringBuilder generatePackage() {
		return new StringBuilder().append("package ").append(packageName)
				.append(";\n");
	}

	public static StringBuilder getImportPackage(LinkedHashSet<String> javaTypes) {
		StringBuilder sb = new StringBuilder();
		for (String javaType : javaTypes) {
			sb.append(javaType);
		}
		return sb;
	}

	public static String generateImportPackage(String packageName) {
		return "import "+packageName +";\n";
	}

	public static StringBuilder generateClassDeclaration(String className) {
		StringBuilder sb = new StringBuilder();
		sb.append("/**\n");
		sb.append(" * auto-generated file.\n");
		sb.append(" * create by EntityGenerator\n");
		sb.append(" * author: lixiaodong\n");
		sb.append(" * create time : " + new SimpleDateFormat("yyyy-MM-dd hh:mm:ss").format(new Date()));
		sb.append("\n */\n");
		sb.append("@SuppressWarnings(\"serial\")\n");
		sb.append("@Table(name=\""+tableName+"\")\n");
		sb.append("public class " + className + " extends BaseDomain {\n ");
		
		return sb;
	}


	public static StringBuilder generateClassFileStr(LinkedHashSet<String> javaTypes,String tableName)
			throws SQLException {
		if("".equals(tableName)){
			throw new SQLException("table name is required!");
		}
		StringBuilder sb = new StringBuilder();
		Connection connection = getConn();
		String sql = "select * from " + tableName;
		ps = connection.prepareStatement(sql);
		rs = ps.executeQuery();
		ResultSetMetaData resultSetMetaData = rs.getMetaData();
		generateClassFieldsSettersGetters(javaTypes,sb, resultSetMetaData);
//		System.out.println(sb.toString());
		closeAll(connection, ps, rs);
		return sb;
	}

	private static void generateClassFieldsSettersGetters(LinkedHashSet<String> javaTypes,StringBuilder sb,
			ResultSetMetaData resultSetMetaData) throws SQLException {
		
		int columnCount = resultSetMetaData.getColumnCount();
		String javaType = "";
		String columnName = "";
		for (int i = 1; i <= columnCount; i++) {
			javaType = convertToJavaType(javaTypes,resultSetMetaData.getColumnTypeName(i));
			boolean isAI = resultSetMetaData.isAutoIncrement(i);
			System.out.println(resultSetMetaData.getColumnLabel(i));
			if(isAI){
				sb.append("\t@Id\n");
				addJavaTypes(javaTypes,"javax.persistence.Id");
			}
			sb.append("\tprivate ").append(javaType).append(" ");
			columnName = lowerCaseFirst(resultSetMetaData.getColumnName(i));
			sb.append(columnName).append(";\n");
			
		}
		
		for(int j = 1; j <= columnCount ; j++){
			javaType = convertToJavaType(javaTypes,resultSetMetaData.getColumnTypeName(j));
			columnName = lowerCaseFirst(resultSetMetaData.getColumnName(j));
			// getters
			sb.append("\tpublic "+javaType+" get"+upperCaseFirst(columnName)+"() {\n");
			sb.append("\t\treturn "+ columnName).append(";\n");
			sb.append("\t}\n");
			
			// setters
			sb.append("\tpublic void set"+upperCaseFirst(columnName)+"("+javaType+" "+columnName+") {\n");
			sb.append("\t\tthis."+ columnName +" = " +columnName).append(";\n");
			sb.append("\t}\n\n");
		}
		
		
		
	}


	/**
	 * Convert jdbc type to java type.
	 * @param type
	 * @return
	 */
	public static String convertToJavaType(LinkedHashSet<String> javaTypes,String type) {
		String str = "Unknown";
		if (type.equals("VARCHAR")) {
			str = "String";
			addJavaTypes(javaTypes,"java.lang.String");
		}
		if (type.equals("INT") || type.equals("INT UNSIGNED")) {
			str = "int";
		}
		if (type.equals("DATETIME")||type.equals("TIMESTAMP")) {
			str = "Date";
			addJavaTypes(javaTypes,"java.util.Date");
		}
		if (type.equals("DECIMAL")||type.equals("DOUBLE")) {
			str = "Double";
			addJavaTypes(javaTypes,"java.lang.Double");
		}
		if(str.equals("Unknown")){
			System.out.println(str+"== > "+type);
		}
		return str;
	}

	public static String upperCaseFirst(String str) {
		return (str != null) ? str.substring(0, 1).toUpperCase()
				+ str.substring(1) : null;
	}
	
	public static String lowerCaseFirst(String str) {
		return (str != null) ? str.substring(0, 1).toLowerCase()
				+ str.substring(1) : null;
	}
	
	public static void generateEntityFile(StringBuilder fileStr,String className,String path) throws IOException{
		File file = new File(path+"\\"+className+".java");
		
		FileWriter fwrite = new FileWriter(file);
		if(!file.exists()){
			file.createNewFile();
		}
		fwrite.write(fileStr.toString());
		fwrite.flush();
		fwrite.close();
		System.out.println("file created!");
	}

}
